package com.cencat.user.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.cencat.common.response.ApiResponse;
import com.cencat.common.response.PageResponse;
import com.cencat.user.dto.UserRoleDTO;
import com.cencat.user.dto.UserRoleQueryDTO;
import com.cencat.user.service.UserRoleService;
import com.cencat.user.vo.UserRoleVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * 用户角色关联管理控制器
 * @author cencat
 * @since 2024-01-01
 */
@RestController
@RequestMapping("/api/user-role")
@Tag(name = "用户角色关联管理", description = "用户角色关联管理相关接口")
@Slf4j
public class UserRoleController {

    @Autowired
    private UserRoleService userRoleService;

    /**
     * 分配用户角色
     * @param dto 用户角色DTO
     * @return 操作结果
     */
    @PostMapping("/assign")
    @Operation(summary = "分配用户角色", description = "为用户分配一个或多个角色")
    public ApiResponse<Boolean> assignUserRoles(@Valid @RequestBody UserRoleDTO dto) {
        try {
            Boolean result = userRoleService.assignUserRoles(dto);
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("分配用户角色失败: {}", e.getMessage(), e);
            return ApiResponse.error("分配用户角色失败: " + e.getMessage());
        }
    }

    /**
     * 移除用户角色
     * @param dto 用户角色DTO
     * @return 操作结果
     */
    @PostMapping("/remove")
    @Operation(summary = "移除用户角色", description = "移除用户的一个或多个角色")
    public ApiResponse<Boolean> removeUserRoles(@Valid @RequestBody UserRoleDTO dto) {
        try {
            Boolean result = userRoleService.removeUserRoles(dto);
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("移除用户角色失败: {}", e.getMessage(), e);
            return ApiResponse.error("移除用户角色失败: " + e.getMessage());
        }
    }

    /**
     * 更新用户角色
     * @param dto 用户角色DTO
     * @return 操作结果
     */
    @PutMapping("/update")
    @Operation(summary = "更新用户角色", description = "更新用户的所有角色（先删除再添加）")
    public ApiResponse<Boolean> updateUserRoles(@Valid @RequestBody UserRoleDTO dto) {
        try {
            Boolean result = userRoleService.updateUserRoles(dto);
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("更新用户角色失败: {}", e.getMessage(), e);
            return ApiResponse.error("更新用户角色失败: " + e.getMessage());
        }
    }

    /**
     * 删除用户的所有角色关联
     * @param userId 用户ID
     * @param tenantId 租户ID
     * @return 操作结果
     */
    @DeleteMapping("/user/{userId}")
    @Operation(summary = "删除用户角色关联", description = "删除指定用户的所有角色关联")
    public ApiResponse<Boolean> deleteUserRolesByUserId(
            @Parameter(description = "用户ID") @PathVariable Long userId,
            @Parameter(description = "租户ID") @RequestParam Long tenantId) {
        try {
            Boolean result = userRoleService.deleteUserRolesByUserId(userId, tenantId);
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("删除用户角色关联失败: {}", e.getMessage(), e);
            return ApiResponse.error("删除用户角色关联失败: " + e.getMessage());
        }
    }

    /**
     * 删除角色的所有用户关联
     * @param roleId 角色ID
     * @param tenantId 租户ID
     * @return 操作结果
     */
    @DeleteMapping("/role/{roleId}")
    @Operation(summary = "删除角色用户关联", description = "删除指定角色的所有用户关联")
    public ApiResponse<Boolean> deleteUserRolesByRoleId(
            @Parameter(description = "角色ID") @PathVariable Long roleId,
            @Parameter(description = "租户ID") @RequestParam Long tenantId) {
        try {
            Boolean result = userRoleService.deleteUserRolesByRoleId(roleId, tenantId);
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("删除角色用户关联失败: {}", e.getMessage(), e);
            return ApiResponse.error("删除角色用户关联失败: " + e.getMessage());
        }
    }

    /**
     * 查询用户角色详情
     * @param userId 用户ID
     * @param tenantId 租户ID
     * @return 用户角色信息
     */
    @GetMapping("/user/{userId}")
    @Operation(summary = "查询用户角色详情", description = "查询指定用户的角色信息")
    public ApiResponse<UserRoleVO> getUserRoleByUserId(
            @Parameter(description = "用户ID") @PathVariable Long userId,
            @Parameter(description = "租户ID") @RequestParam Long tenantId) {
        try {
            UserRoleVO result = userRoleService.getUserRoleByUserId(userId, tenantId);
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("查询用户角色详情失败: {}", e.getMessage(), e);
            return ApiResponse.error("查询用户角色详情失败: " + e.getMessage());
        }
    }

    /**
     * 分页查询用户角色关联
     * @param queryDTO 查询条件
     * @return 分页结果
     */
    @PostMapping("/page")
    @Operation(summary = "分页查询用户角色关联", description = "根据条件分页查询用户角色关联信息")
    public ApiResponse<PageResponse<UserRoleVO>> getUserRolePage(@Valid @RequestBody UserRoleQueryDTO queryDTO) {
        try {
            PageResponse<UserRoleVO> userRolePage = userRoleService.getUserRolePage(queryDTO);
            return ApiResponse.success(userRolePage);
        } catch (Exception e) {
            log.error("分页查询用户角色关联失败: {}", e.getMessage(), e);
            return ApiResponse.error("分页查询用户角色关联失败: " + e.getMessage());
        }
    }

    /**
     * 查询用户角色关联列表
     * @param queryDTO 查询条件
     * @return 用户角色关联列表
     */
    @PostMapping("/list")
    @Operation(summary = "查询用户角色关联列表", description = "根据条件查询用户角色关联列表")
    public ApiResponse<List<UserRoleVO>> getUserRoleList(@Valid @RequestBody UserRoleQueryDTO queryDTO) {
        try {
            List<UserRoleVO> result = userRoleService.getUserRoleList(queryDTO);
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("查询用户角色关联列表失败: {}", e.getMessage(), e);
            return ApiResponse.error("查询用户角色关联列表失败: " + e.getMessage());
        }
    }

    /**
     * 检查用户是否拥有指定角色
     * @param userId 用户ID
     * @param roleId 角色ID
     * @param tenantId 租户ID
     * @return 检查结果
     */
    @GetMapping("/check")
    @Operation(summary = "检查用户角色", description = "检查用户是否拥有指定角色")
    public ApiResponse<Boolean> checkUserHasRole(
            @Parameter(description = "用户ID") @RequestParam Long userId,
            @Parameter(description = "角色ID") @RequestParam Long roleId,
            @Parameter(description = "租户ID") @RequestParam Long tenantId) {
        try {
            Boolean result = userRoleService.checkUserHasRole(userId, roleId, tenantId);
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("检查用户角色失败: {}", e.getMessage(), e);
            return ApiResponse.error("检查用户角色失败: " + e.getMessage());
        }
    }

    /**
     * 检查用户是否拥有指定角色编码
     * @param userId 用户ID
     * @param roleCode 角色编码
     * @param tenantId 租户ID
     * @return 检查结果
     */
    @GetMapping("/check-code")
    @Operation(summary = "检查用户角色编码", description = "检查用户是否拥有指定角色编码")
    public ApiResponse<Boolean> checkUserHasRoleCode(
            @Parameter(description = "用户ID") @RequestParam Long userId,
            @Parameter(description = "角色编码") @RequestParam String roleCode,
            @Parameter(description = "租户ID") @RequestParam Long tenantId) {
        try {
            Boolean result = userRoleService.checkUserHasRoleCode(userId, roleCode, tenantId);
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("检查用户角色编码失败: {}", e.getMessage(), e);
            return ApiResponse.error("检查用户角色编码失败: " + e.getMessage());
        }
    }

    /**
     * 根据角色ID查询用户ID列表
     * @param roleIds 角色ID列表
     * @param tenantId 租户ID
     * @return 用户ID列表
     */
    @PostMapping("/users-by-roles")
    @Operation(summary = "根据角色查询用户", description = "根据角色ID列表查询用户ID列表")
    public ApiResponse<List<Long>> getUserIdsByRoleIds(
            @Parameter(description = "角色ID列表") @RequestBody List<Long> roleIds,
            @Parameter(description = "租户ID") @RequestParam Long tenantId) {
        try {
            List<Long> result = userRoleService.getUserIdsByRoleIds(roleIds, tenantId);
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("根据角色查询用户失败: {}", e.getMessage(), e);
            return ApiResponse.error("根据角色查询用户失败: " + e.getMessage());
        }
    }

    /**
     * 根据用户ID查询角色ID列表
     * @param userIds 用户ID列表
     * @param tenantId 租户ID
     * @return 角色ID列表
     */
    @PostMapping("/roles-by-users")
    @Operation(summary = "根据用户查询角色", description = "根据用户ID列表查询角色ID列表")
    public ApiResponse<List<Long>> getRoleIdsByUserIds(
            @Parameter(description = "用户ID列表") @RequestBody List<Long> userIds,
            @Parameter(description = "租户ID") @RequestParam Long tenantId) {
        try {
            List<Long> result = userRoleService.getRoleIdsByUserIds(userIds, tenantId);
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("根据用户查询角色失败: {}", e.getMessage(), e);
            return ApiResponse.error("根据用户查询角色失败: " + e.getMessage());
        }
    }

    /**
     * 统计用户角色关联数量
     * @param tenantId 租户ID
     * @return 关联数量
     */
    @GetMapping("/count")
    @Operation(summary = "统计用户角色关联数量", description = "统计指定租户的用户角色关联总数")
    public ApiResponse<Long> getUserRoleCount(@Parameter(description = "租户ID") @RequestParam Long tenantId) {
        try {
            Long result = userRoleService.getUserRoleCount(tenantId);
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("统计用户角色关联数量失败: {}", e.getMessage(), e);
            return ApiResponse.error("统计用户角色关联数量失败: " + e.getMessage());
        }
    }

    /**
     * 统计用户的角色数量
     * @param userId 用户ID
     * @param tenantId 租户ID
     * @return 角色数量
     */
    @GetMapping("/count/user/{userId}")
    @Operation(summary = "统计用户角色数量", description = "统计指定用户的角色数量")
    public ApiResponse<Long> getRoleCountByUserId(
            @Parameter(description = "用户ID") @PathVariable Long userId,
            @Parameter(description = "租户ID") @RequestParam Long tenantId) {
        try {
            Long result = userRoleService.getRoleCountByUserId(userId, tenantId);
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("统计用户角色数量失败: {}", e.getMessage(), e);
            return ApiResponse.error("统计用户角色数量失败: " + e.getMessage());
        }
    }

    /**
     * 统计角色的用户数量
     * @param roleId 角色ID
     * @param tenantId 租户ID
     * @return 用户数量
     */
    @GetMapping("/count/role/{roleId}")
    @Operation(summary = "统计角色用户数量", description = "统计指定角色的用户数量")
    public ApiResponse<Long> getUserCountByRoleId(
            @Parameter(description = "角色ID") @PathVariable Long roleId,
            @Parameter(description = "租户ID") @RequestParam Long tenantId) {
        try {
            Long result = userRoleService.getUserCountByRoleId(roleId, tenantId);
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("统计角色用户数量失败: {}", e.getMessage(), e);
            return ApiResponse.error("统计角色用户数量失败: " + e.getMessage());
        }
    }

    /**
     * 批量分配角色给用户
     * @param request 批量分配请求
     * @return 操作结果
     */
    @PostMapping("/batch-assign")
    @Operation(summary = "批量分配角色给用户", description = "批量为多个用户分配多个角色")
    public ApiResponse<Boolean> batchAssignRolesToUsers(@Valid @RequestBody BatchAssignRequest request) {
        try {
            Boolean result = userRoleService.batchAssignRolesToUsers(request.getUserIds(), request.getRoleIds(), request.getTenantId());
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("批量分配角色给用户失败: {}", e.getMessage(), e);
            return ApiResponse.error("批量分配角色给用户失败: " + e.getMessage());
        }
    }

    /**
     * 批量移除用户角色
     * @param request 批量移除请求
     * @return 操作结果
     */
    @PostMapping("/batch-remove")
    @Operation(summary = "批量移除用户角色", description = "批量移除多个用户的多个角色")
    public ApiResponse<Boolean> batchRemoveRolesFromUsers(@Valid @RequestBody BatchRemoveRequest request) {
        try {
            Boolean result = userRoleService.batchRemoveRolesFromUsers(request.getUserIds(), request.getRoleIds(), request.getTenantId());
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("批量移除用户角色失败: {}", e.getMessage(), e);
            return ApiResponse.error("批量移除用户角色失败: " + e.getMessage());
        }
    }

    /**
     * 复制用户角色
     * @param request 复制请求
     * @return 操作结果
     */
    @PostMapping("/copy")
    @Operation(summary = "复制用户角色", description = "将源用户的角色复制给目标用户")
    public ApiResponse<Boolean> copyUserRoles(@Valid @RequestBody CopyUserRolesRequest request) {
        try {
            Boolean result = userRoleService.copyUserRoles(request.getSourceUserId(), request.getTargetUserId(), request.getTenantId());
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("复制用户角色失败: {}", e.getMessage(), e);
            return ApiResponse.error("复制用户角色失败: " + e.getMessage());
        }
    }

    /**
     * 同步用户角色
     * @param userId 用户ID
     * @param tenantId 租户ID
     * @return 操作结果
     */
    @PostMapping("/sync/{userId}")
    @Operation(summary = "同步用户角色", description = "根据用户信息自动同步角色")
    public ApiResponse<Boolean> syncUserRoles(
            @Parameter(description = "用户ID") @PathVariable Long userId,
            @Parameter(description = "租户ID") @RequestParam Long tenantId) {
        try {
            Boolean result = userRoleService.syncUserRoles(userId, tenantId);
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("同步用户角色失败: {}", e.getMessage(), e);
            return ApiResponse.error("同步用户角色失败: " + e.getMessage());
        }
    }

    /**
     * 批量分配请求
     */
    public static class BatchAssignRequest {
        private List<Long> userIds;
        private List<Long> roleIds;
        private Long tenantId;

        // getters and setters
        public List<Long> getUserIds() {
            return userIds;
        }

        public void setUserIds(List<Long> userIds) {
            this.userIds = userIds;
        }

        public List<Long> getRoleIds() {
            return roleIds;
        }

        public void setRoleIds(List<Long> roleIds) {
            this.roleIds = roleIds;
        }

        public Long getTenantId() {
            return tenantId;
        }

        public void setTenantId(Long tenantId) {
            this.tenantId = tenantId;
        }
    }

    /**
     * 批量移除请求
     */
    public static class BatchRemoveRequest {
        private List<Long> userIds;
        private List<Long> roleIds;
        private Long tenantId;

        // getters and setters
        public List<Long> getUserIds() {
            return userIds;
        }

        public void setUserIds(List<Long> userIds) {
            this.userIds = userIds;
        }

        public List<Long> getRoleIds() {
            return roleIds;
        }

        public void setRoleIds(List<Long> roleIds) {
            this.roleIds = roleIds;
        }

        public Long getTenantId() {
            return tenantId;
        }

        public void setTenantId(Long tenantId) {
            this.tenantId = tenantId;
        }
    }

    /**
     * 复制用户角色请求
     */
    public static class CopyUserRolesRequest {
        private Long sourceUserId;
        private Long targetUserId;
        private Long tenantId;

        // getters and setters
        public Long getSourceUserId() {
            return sourceUserId;
        }

        public void setSourceUserId(Long sourceUserId) {
            this.sourceUserId = sourceUserId;
        }

        public Long getTargetUserId() {
            return targetUserId;
        }

        public void setTargetUserId(Long targetUserId) {
            this.targetUserId = targetUserId;
        }

        public Long getTenantId() {
            return tenantId;
        }

        public void setTenantId(Long tenantId) {
            this.tenantId = tenantId;
        }
    }

}